<template>
    <div>

        <Row style="margin-top:10px;margin-bottom:10px;">
            <Col span="17">
                <Button class="ivu-btn-default" @click="createRootNode">创建一级部门</Button>
                <Button class="ivu-btn-default" @click="save">保存</Button>
                <Button class="ivu-btn-default" @click="submint">提交</Button>
            </Col>
        </Row>
        <div style="width: 100%; display: flex; justify-content: space-between">
            <div ref="diagram" style="flex-grow: 1; height: 450px;"></div>
            <div>
                <div>
                    <Form ref="formValidate" v-show="orgEditorShow" :model="selectedOrg" :rules="orgValidateRule" :label-width="80">
                        <FormItem label="部门" prop="organization">
                            <Input placeholder="请输入部门名称" v-model="selectedOrg.organization"></Input>
                        </FormItem>
                        <FormItem label="职位" prop="position">
                            <AutoComplete
                                    v-model="selectedOrg.position"
                                    @on-search="searchPosition"
                                    @on-select="selectPosition"
                                    placeholder="请输入职位"
                                    style="width:200px">
                                <Option v-for="item in positionList" :value="item.name" :key="item.id">{{ item.name }}
                                </Option>
                            </AutoComplete>
                        </FormItem>
                        <FormItem label="姓名" prop="name">
                            <AutoComplete
                                    v-model="selectedOrg.name"
                                    @on-search="searchUser"
                                    @on-select="selectUser"
                                    placeholder="请输入姓名"
                                    style="width:200px">
                                <Option v-for="item in userList" :value="item.name" :key="item.id">{{ item.name }}
                                </Option>
                            </AutoComplete>
                        </FormItem>
                        <FormItem label="手机号" prop="mobile">
                            <Input placeholder="请输入手机号" v-model="selectedOrg.mobile"></Input>
                        </FormItem>
                    </Form>
                </div>
            </div>
        </div>
    </div>
</template>
<script>
    import go from 'gojs';
    var $ = go.GraphObject.make;
    var nodeIdCounter = -1; // use a sequence to guarantee key uniqueness as we add/remove/modify nodes

    export default {
        name: 'orgEditor',
        data () {
            // 校验手机号
            const validateMobile = (rule, value, callback) => {
                if (value === '') {
                    callback(new Error('手机号为必填项'));
                } else {
                    var mobileReg = /^[1][0-9]{10}$/;
                    if (!mobileReg.test(value)) {
                        callback(new Error('手机号格式不正确'));
                    } else {
                        callback();
                    }
                }
            };
            return {
    
                ruleCustom: {
                    passwd: [
                        { validator: validatePass, trigger: 'blur' }
                    ],
                    passwdCheck: [
                        { validator: validatePassCheck, trigger: 'blur' }
                    ],
                    age: [
                        { validator: validateAge, trigger: 'blur' }
                    ]

                },

                diagram: null,
                userEditorVisible: false,
                inspectedObject: null,
                blankOrg:
                    {
                        organization: '',
                        position: '',
                        name: '',
                        mobile: ''
                    },
                selectedOrg:
                    {
                        organization: '',
                        position: '',
                        name: '',
                        mobile: ''
                    },
                orgValidateRule: {
                    organization: [
                        { required: true, message: '部门为必填项', trigger: 'blur' }
                    ],
                    position: [
                        { required: true, message: '职位为必填项', trigger: 'blur' }
                    ],
                    name: [
                        { required: true, message: '姓名为必填项', trigger: 'blur' }
                    ],
                    mobile: { validator: validateMobile, trigger: 'blur', required: true }
                },
                orgEditorShow: false,
                positionList: [],
                positionDbList: [],
                userList: [],
                userDbList: [],
                diagramData: {
                    'class': 'go.TreeModel',
                    'nodeDataArray': [
                    ]
                }
            };
        },
        mounted () {
            var self = this;
            this.initData();
            var myDiagram =
                $(go.Diagram, this.$refs.diagram,
                    {
                        initialContentAlignment: go.Spot.Center,
                        maxSelectionCount: 1, // users can select only one part at a time,
                        validCycle: go.Diagram.CycleDestinationTree, // make sure users can only create trees
                        'clickCreatingTool.archetypeNodeData': {}, // allow double-click in background to create a new node
                        'clickCreatingTool.insertPart': function (loc) { // customize the data for the new node
                            this.archetypeNodeData = {
                                key: this.getNextKey(), // assign the key based on the number of nodes
                                position: '职位',
                                title: ''
                            };
                            return go.ClickCreatingTool.prototype.insertPart.call(this, loc);
                        },
                        layout:
                            $(go.TreeLayout,
                                {
                                    treeStyle: go.TreeLayout.StyleLastParents,
                                    arrangement: go.TreeLayout.ArrangementHorizontal,
                                    // properties for most of the tree:
                                    angle: 90,
                                    layerSpacing: 35,
                                    // properties for the "last parents":
                                    alternateAngle: 90,
                                    alternateLayerSpacing: 35,
                                    alternateAlignment: go.TreeLayout.AlignmentBus,
                                    alternateNodeSpacing: 20
                                }),
                        'undoManager.isEnabled': true // enable undo & redo
                    });

            // manage boss info manually when a node or link is deleted from the diagram
            myDiagram.addDiagramListener('SelectionDeleting', function (e) {
                var part = e.subject.first(); // e.subject is the myDiagram.selection collection,
                // so we'll get the first since we know we only have one selection
                myDiagram.startTransaction('clear boss');
                if (part instanceof go.Node) {
                    var it = part.findTreeChildrenNodes(); // find all child nodes
                    while (it.next()) { // now iterate through them and clear out the boss information
                        var child = it.value;
                        var bossText = child.findObject('boss'); // since the boss TextBlock is named, we can access it by name
                        if (bossText === null) return;
                        bossText.text = '';
                    }
                } else if (part instanceof go.Link) {
                    var child = part.toNode;
                    var bossText = child.findObject('boss'); // since the boss TextBlock is named, we can access it by name
                    if (bossText === null) return;
                    bossText.text = '';
                }
                myDiagram.commitTransaction('clear boss');
            });

            myDiagram.addDiagramListener('ChangedSelection', function (e) {
                self.inspectObject();
            });
            var levelColors = ['#AC193D', '#2672EC', '#8C0095', '#5133AB',
                '#008299', '#D24726', '#008A00', '#094AB2'];
            // override TreeLayout.commitNodes to also modify the background brush based on the tree depth level
            myDiagram.layout.commitNodes = function () {
                go.TreeLayout.prototype.commitNodes.call(myDiagram.layout); // do the standard behavior
                // then go through all of the vertexes and set their corresponding node's Shape.fill
                // to a brush dependent on the TreeVertex.level value
                myDiagram.layout.network.vertexes.each(function (v) {
                    if (v.node) {
                        var level = v.level % (levelColors.length);
                        var color = levelColors[level];
                        var shape = v.node.findObject('SHAPE');
                        if (shape) {
                            shape.fill = $(go.Brush, 'Linear', {
                                0: color,
                                1: go.Brush.lightenBy(color, 0.05),
                                start: go.Spot.Left,
                                end: go.Spot.Right
                            });
                        }
                    }
                });
            };

            // define the Node template
            myDiagram.nodeTemplate =
                $(go.Node, 'Auto',
                    { // handle dragging a Node onto a Node to (maybe) change the reporting relationship
                        mouseDragEnter: function (e, node, prev) {
                            var diagram = node.diagram;
                            var selnode = diagram.selection.first();
                            if (!mayWorkFor(selnode, node)) return;
                            var shape = node.findObject('SHAPE');
                            if (shape) {
                                shape._prevFill = shape.fill; // remember the original brush
                                shape.fill = 'darkred';
                            }
                        },
                        mouseDragLeave: function (e, node, next) {
                            var shape = node.findObject('SHAPE');
                            if (shape && shape._prevFill) {
                                shape.fill = shape._prevFill; // restore the original brush
                            }
                        },
                        mouseDrop: function (e, node) {
                            var diagram = node.diagram;
                            var selnode = diagram.selection.first(); // assume just one Node in selection
                            if (mayWorkFor(selnode, node)) {
                                // find any existing link into the selected node
                                var link = selnode.findTreeParentLink();
                                if (link !== null) { // reconnect any existing link
                                    link.fromNode = node;
                                } else { // else create a new link
                                    diagram.toolManager.linkingTool.insertLink(node, node.port, selnode, selnode.port);
                                }
                            }
                        }
                    },
                    // for sorting, have the Node.text be the data.name
                    new go.Binding('text', 'position'),
                    // bind the Part.layerName to control the Node's layer depending on whether it isSelected
                    new go.Binding('layerName', 'isSelected', function (sel) {
                        return sel ? 'Foreground' : '';
                    }).ofObject(),
                    // define the node's outer shape
                    $(go.Shape, 'Rectangle',
                        {
                            name: 'SHAPE',
                            fill: 'white',
                            stroke: null,
                            // set the port properties:
                            portId: '',
                            fromLinkable: true,
                            toLinkable: true,
                            cursor: 'pointer'
                        }),
                    $(go.Panel, 'Horizontal',
                        $(go.Picture,
                            {
                                name: 'Picture',
                                desiredSize: new go.Size(39, 50),
                                margin: new go.Margin(6, 8, 6, 10)
                            },
                            new go.Binding('source', 'key', this.findHeadShot)),
                        // define the panel where the text will appear
                        $(go.Panel, 'Table',
                            {
                                maxSize: new go.Size(230, 999),
                                margin: new go.Margin(6, 8, 6, 10),
                                defaultAlignment: go.Spot.Left
                            },
                            $(go.RowColumnDefinition, {column: 2, width: 1}),
                            $(go.TextBlock, this.textStyle(), // the name
                                {
                                    row: 0,
                                    column: 0,
                                    columnSpan: 2,
                                    font: '12pt Segoe UI,sans-serif',
                                    editable: false,
                                    isMultiline: false,
                                    minSize: new go.Size(10, 16)
                                },
                                new go.Binding('text', 'organization').makeTwoWay()),
                            $(go.TextBlock, '职位: ', this.textStyle(),
                                {row: 1, column: 0}),
                            $(go.TextBlock, this.textStyle(),
                                {
                                    row: 1,
                                    column: 1,
                                    editable: false,
                                    isMultiline: false,
                                    minSize: new go.Size(10, 14),
                                    margin: new go.Margin(0, 0, 0, 3)
                                },
                                new go.Binding('text', 'position').makeTwoWay()),
                            $(go.TextBlock, '姓名: ', this.textStyle(),
                                {row: 3, column: 0}),
                            $(go.TextBlock, this.textStyle(),
                                {
                                    row: 3,
                                    column: 1,
                                    editable: false,
                                    isMultiline: false,
                                    minSize: new go.Size(10, 14),
                                    margin: new go.Margin(0, 0, 0, 3)
                                },
                                new go.Binding('text', 'name').makeTwoWay())
                        ) // end Table Panel
                    ) // end Horizontal Panel
                ); // end Node

            // the context menu allows users to make a position vacant,
            // remove a role and reassign the subtree, or remove a organization
            myDiagram.nodeTemplate.contextMenu =
                $(go.Adornment, 'Vertical',
                    $('ContextMenuButton',
                        $(go.TextBlock, '创建子部门'),
                        {
                            click: function (e, obj) {
                                var node = obj.part.adornedPart;
                                if (node !== null) {
                                    var thisemp = node.data;
                                    myDiagram.startTransaction('createDepartmentOrPosition');
                                    var newemp = {
                                        key: self.getNextKey(),
                                        'organization': '',
                                        'position': '',
                                        'name': '',
                                        'mobile': '',
                                        parent: thisemp.key,
                                        isSelected: true
                                    };
                                    myDiagram.model.addNodeData(newemp);
                                    myDiagram.select(myDiagram.findNodeForKey(newemp.key));
                                    myDiagram.commitTransaction('createDepartmentOrPosition');
                                }
                            }
                        }
                    ),
                    $('ContextMenuButton',
                        $(go.TextBlock, '复制'),
                        {
                            click: function (e, obj) {
                                var node = obj.part.adornedPart;
                                if (node !== null) {
                                    var thisemp = node.data;
                                    myDiagram.startTransaction('createDepartmentOrPosition');
                                    var newemp = {
                                        key: self.getNextKey(),
                                        'organization': thisemp['organization'],
                                        'organizationId': thisemp['organizationId'],
                                        'position': thisemp['position'],
                                        'positionId': thisemp['positionId'],
                                        'name': thisemp['name'],
                                        'userId': thisemp['userId'],
                                        'mobile': thisemp['mobile'],
                                        parent: thisemp.parent
                                    };
                                    myDiagram.model.addNodeData(newemp);
                                    myDiagram.select(myDiagram.findNodeForKey(newemp.key));
                                    myDiagram.commitTransaction('createDepartmentOrPosition');
                                }
                            }
                        }
                    ),
                    $('ContextMenuButton',
                        $(go.TextBlock, '删除'),
                        {
                            click: function (e, obj) {
                                // remove the whole subtree, including the node itself
                                var node = obj.part.adornedPart;
                                if (node !== null) {
                                    myDiagram.startTransaction('remove dept');
                                    myDiagram.removeParts(node.findTreeParts());
                                    self.selectedOrg = self.blankOrg;
                                    myDiagram.commitTransaction('remove dept');
                                }
                            }
                        }
                    )
                );
            // define the Link template
            myDiagram.linkTemplate =
                $(go.Link, go.Link.Orthogonal,
                    {corner: 5, relinkableFrom: true, relinkableTo: true},
                    $(go.Shape, {strokeWidth: 4, stroke: '#00a4a4'})); // the link shape

            this.diagram = myDiagram;

            this.diagramData = localStorage.getItem('diagramData') ? JSON.parse(localStorage.getItem('diagramData')) : this.diagramData;
            myDiagram.model = go.Model.fromJson(this.diagramData);
        },
        methods: {
            initData () {
                // 获取组织架构图
                depot.get({
                    url: this.URL.USER.FIND_GRAPHIC_DATA,
                    cb: (data) => {
                        console.log(1222);
                        if (data.code === 0) {
                            console.log(data.data);
                            // this.positionDbList = data.data;
                        } else if (data.code === 999) {
                            this.$Message.error(data.message);
                        }
                    }
                });
                // 获取职位信息
                depot.get({
                    url: this.URL.USER.FIND_POSITION_LIST,
                    cb: (data) => {
                        if (data.code === 0) {
                            this.positionDbList = data.data;
                        } else if (data.code === 999) {
                            this.$Message.error(data.message);
                        }
                    }
                });
            },
            save () {
                localStorage.setItem('diagramData', this.diagram.model.toJson());
            },
            // This function is used to find a suitable ID when modifying/creating nodes.
            // We used the counter combined with findNodeDataForKey to ensure uniqueness.
            getNextKey () {
                var key = nodeIdCounter;
                while (this.diagram.model.findNodeDataForKey(key) !== null) {
                    key = nodeIdCounter--;
                }
                return key;
            },
            // 编辑
            edit (e, obj) {
            },
            // This function provides a common style for most of the TextBlocks.
            // Some of these values may be overridden in a particular TextBlock.
            textStyle () {
                return {font: '9pt  Segoe UI,sans-serif', stroke: 'white'};
            },
            // This converter is used by the Picture.
            findHeadShot (key) {
                if (key < 0 || key > 16) return 'http://www.scrm.com/images/HSnopic.png'; // There are only 16 images on the server
                return 'http://www.scrm.com/images/HSnopic.png';
            },
            inspectObject (object) {
                var inspectedObject = null;
                if (object === null) return;
                if (object === undefined) {
                    inspectedObject = this.diagram.selection.first();
                } else { // if object was passed in as a parameter
                    inspectedObject = object;
                }
                if (inspectedObject === null || this.inspectedObject === inspectedObject) {
                    this.inspectedObject = inspectedObject;
                    this.orgEditorShow = false;
                    this.selectedOrg = this.blankOrg;
                    return;
                }
                this.inspectedObject = inspectedObject;
                if (this.inspectObject === null) return;
                var data = (inspectedObject instanceof go.Part) ? inspectedObject.data : inspectedObject;
                if (!data) return;

                if (inspectedObject instanceof go.Node) {
                    this.orgEditorShow = true;
                    // this.selectedOrg = data;
                    this.selectedOrg['organization'] = data['organization'];
                    this.selectedOrg['position'] = data['position'];
                    this.selectedOrg['name'] = data['name'];
                    this.selectedOrg['mobile'] = data['mobile'];
                } else {
                    this.selectedOrg = this.blankOrg;
                    this.orgEditorShow = false;
                }
            },
            setNodeValue (key, value) {
                if (!this.selectedOrg) {
                    return;
                }
                if (!this.diagramData) {
                    return;
                }
                this.inspectedObject = this.diagram.selection.first();
                var isPart = this.inspectedObject instanceof go.Part;
                var data = isPart ? this.inspectedObject.data : this.inspectedObject;
                if (!data) { return; } // must not try to update data when there's no data!
                this.diagram.model.setDataProperty(data, key, value);
            },
            createRootNode () {
                this.diagram.startTransaction('createDepartmentOrPosition');
                var newemp = {
                    key: this.getNextKey(),
                    'organization': '',
                    'position': '',
                    'name': '',
                    'mobile': '',
                    'nodeType': 'department'
                };
                this.diagram.model.addNodeData(newemp);
                this.diagram.commitTransaction('createDepartmentOrPosition');
            },
            searchPosition (value) {
                this.positionList = [];
                if (this.positionDbList) {
                    this.positionDbList.forEach(position => {
                        if (position.name) {
                            if (position.name.indexOf(value) == 0) {
                                this.positionList.push(position);
                            }
                        }
                    });
                    if (this.positionList.length == 0) {
                        this.setNodeValue('position', value);
                        this.setNodeValue('positionId', null);
                    }
                    if (this.positionList.length == 1) {
                        var position = this.positionList[0];
                        this.positionList = [];
                        this.setNodeValue('position', position.name);
                        this.setNodeValue('positionId', position.id);
                    }
                }
            },
            selectPosition (obj) {
                this.setNodeValue('position', obj);
                if (this.positionList) {
                    this.positionList.forEach(position => {
                        if (position.name) {
                            if (position.name === obj) {
                                this.setNodeValue('positionId', position.id);
                            }
                        }
                    });
                }
            },
            searchUser (value) {
                this.userList = [];
                if (this.userDbList) {
                    this.userDbList.forEach(user => {
                        if (user.name) {
                            if (user.name.indexOf(value) == 0) {
                                this.userList.push(user);
                            }
                        }
                    });
                    if (this.userList.length == 0) {
                        this.setNodeValue('name', value);
                        this.setNodeValue('userId', null);
                    }
                    if (this.userList.length == 1) {
                        var user = this.userList[0];
                        this.userList = [];
                        this.setNodeValue('name', user.name);
                        this.setNodeValue('userId', user.id);
                    }
                }
            },
            selectUser (obj) {
                this.setNodeValue('user', obj);
                if (this.userList) {
                    this.userList.forEach(user => {
                        if (user.name) {
                            if (user.name === obj) {
                                this.setNodeValue('userId', user.id);
                            }
                        }
                    });
                }
            }
        },
        watch: {
            'selectedOrg.organization' (newValue) {
                this.setNodeValue('organization', newValue);
            },
            // 'selectedOrg.position'(newValue) {
            //     this.setNodeValue('position', newValue);
            // },
            // 'selectedOrg.name'(newValue) {
            //     this.setNodeValue('name', newValue);
            // },
            'selectedOrg.mobile' (newValue) {
                this.setNodeValue('mobile', newValue);
            }
        }
    };
</script>
